package com.huohuzhihui.api.service.impl;

import com.alibaba.fastjson.JSON;
import com.huohuzhihui.account.domain.AccUserAccount;
import com.huohuzhihui.account.mapper.AccUserAccountMapper;
import com.huohuzhihui.api.service.ApiAccountService;
import com.huohuzhihui.common.core.domain.entity.SysUser;
import com.huohuzhihui.common.core.domain.model.LoginUser;
import com.huohuzhihui.common.core.redis.RedisCache;
import com.huohuzhihui.common.exception.CustomException;
import com.huohuzhihui.common.exception.user.UserPasswordNotMatchException;
import com.huohuzhihui.common.utils.DateUtils;
import com.huohuzhihui.common.utils.SecurityUtils;
import com.huohuzhihui.common.utils.uuid.IdUtils;
import com.huohuzhihui.framework.web.service.TokenService;
import com.huohuzhihui.system.mapper.SysUserMapper;
import com.huohuzhihui.system.service.ISysConfigService;
import com.huohuzhihui.trade.domain.AccTradeRecord;
import com.huohuzhihui.trade.domain.TradeOrder;
import com.huohuzhihui.trade.mapper.AccTradeRecordMapper;
import com.huohuzhihui.trade.mapper.TradeOrderMapper;
import com.huohuzhihui.trade.service.ITradeOrderService;
import com.ijpay.core.enums.SignType;
import com.ijpay.core.enums.TradeType;
import com.ijpay.core.kit.HttpKit;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.WxPayApiConfig;
import com.ijpay.wxpay.model.UnifiedOrderModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 订单Service业务层处理
 * 
 * @author huohuzhihui
 * @date 2020-11-15
 */
@Service
public class ApiAccountServiceImpl implements ApiAccountService {
    @Autowired
    private AccUserAccountMapper accUserAccountMapper;
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private TradeOrderMapper tradeOrderMapper;
    @Autowired
    private ISysConfigService sysConfigService;
    @Autowired
    private ITradeOrderService iTradeOrderService;
    @Autowired
    private AccTradeRecordMapper accTradeRecordMapper;

    @Autowired
    private TokenService tokenService;

    @Resource
    private AuthenticationManager authenticationManager;

    @Autowired
    private RedisCache redisCache;



    @Value("${wxpay.appId}")
    private String appId;

    @Value("${wxpay.appSecret}")
    private String appSecret;

    @Value("${wxpay.certPath}")
    private String certPath;

    @Value("${wxpay.domain}")
    private String domain;

    @Value("${wxpay.mchId}")
    private String mchId;

    @Value("${wxpay.partnerKey}")
    private String partnerKey;
    @Value("${wxpay.notifyUrl}")
    private String notifyUrl;
    @Value("${wxpay.refundNotifyUrl}")
    private String refundNotifyUrl;

    private WxPayApiConfig wxPayApiConfig;
    @PostConstruct
    public WxPayApiConfig getApiConfig() {
        wxPayApiConfig = WxPayApiConfig.builder()
                    .appId(appId)
                    .mchId(mchId)
                    .partnerKey(partnerKey)
                    .certPath(certPath)
                    .domain(domain)
                    .build();
        return wxPayApiConfig;
    }
    @Override
    public AccUserAccount getAccountByPhonenumber(String phonenumber) {
        SysUser sysUser = sysUserMapper.selectUserByPhonenumber(phonenumber);
        if(sysUser==null){
            return null;
        }
        return accUserAccountMapper.selectAccUserAccountByUserId(sysUser.getUserId());
    }

    @Override
    public AccUserAccount getAccountById(Long accountId) {
        return accUserAccountMapper.selectAccUserAccountById(accountId);
    }

    @Override
    public AccUserAccount getAccountByUserId(Long userId) {
        SysUser sysUser = sysUserMapper.selectUserById(userId);
        if(sysUser==null){
            return null;
        }
        return accUserAccountMapper.selectAccUserAccountByUserId(sysUser.getUserId());
    }

    @Override
    public SysUser getUserByPhonenumber(String phonenumber) {
        return sysUserMapper.selectUserByPhonenumber(phonenumber);
    }

    @Override
    public SysUser getUserById(Long userId) {
        return this.sysUserMapper.selectUserById(userId);
    }


    @Override
    public int resetPassword(String userName, String newPassword) {
        return sysUserMapper.resetUserPwd(userName, SecurityUtils.encryptPassword(newPassword));
    }

    @Override
    public BigDecimal getSumTrade(TradeOrder tradeOrder) {
        return tradeOrderMapper.getOrderStatistics(tradeOrder);
    }

    @Override
    public List<TradeOrder> findAccountTradeRecordList(TradeOrder tradeOrder) {
        return tradeOrderMapper.selectTradeOrderList(tradeOrder);
    }

    @Override
    public String recharge(AccUserAccount accUserAccount, BigDecimal amount, String source, String channelCode,String openId,String ip) {
        if(accUserAccount != null) {
            String type = "0";//充值
            Long deviceId = null;
            String cardNo = "";
            String tradeNo = IdUtils.fastSimpleUUID();

            iTradeOrderService.insertTradeOrder(type, accUserAccount.getId(), accUserAccount.getUserName(), amount, source, deviceId, channelCode, accUserAccount.getUserName(),tradeNo);

            String subject = "一卡通充值";
            String body = "一卡通充值";

            Map<String, String> params = UnifiedOrderModel
                    .builder()
                    .appid(wxPayApiConfig.getAppId())
                    .mch_id(wxPayApiConfig.getMchId())
                    .nonce_str(WxPayKit.generateStr())
                    .body(body)
                    .attach(subject)
                    .out_trade_no(tradeNo)
                    .total_fee(amount.multiply(new BigDecimal("100")).stripTrailingZeros().toPlainString())
                    .spbill_create_ip(ip)
                    .notify_url(notifyUrl)
                    .trade_type(TradeType.JSAPI.getTradeType())
                    .openid(openId)
                    .build()
                    .createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);

            String xmlResult = WxPayApi.pushOrder(false, params);

            Map<String, String> result = WxPayKit.xmlToMap(xmlResult);

            String returnCode = result.get("return_code");
            String returnMsg = result.get("return_msg");
            if (!WxPayKit.codeIsOk(returnCode)) {
                throw new CustomException(returnMsg,500);
            }
            String resultCode = result.get("result_code");
            if (!WxPayKit.codeIsOk(resultCode)) {
                throw new CustomException(returnMsg,500);
            }
            // 以下字段在 return_code 和 result_code 都为 SUCCESS 的时候有返回
            String prepayId = result.get("prepay_id");
            Map<String, String> packageParams = WxPayKit.miniAppPrepayIdCreateSign(wxPayApiConfig.getAppId(), prepayId,
                    wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
            String jsonStr = JSON.toJSONString(packageParams);
            System.out.println("支付结果------------------"+jsonStr);
            return jsonStr;
        }
        return null;
    }

    @Override
    public String wxPayNotify(HttpServletRequest request) {
        String xmlMsg = HttpKit.readData(request);
        Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);
        String returnCode = params.get("return_code");

        // 注意重复通知的情况，同一订单号可能收到多次通知，请注意一定先判断订单状态
        // 注意此处签名方式需与统一下单的签名类型一致
        if (WxPayKit.verifyNotify(params, partnerKey, SignType.HMACSHA256)) {
            if (WxPayKit.codeIsOk(returnCode)) {
                String tradeNo = params.get("out_trade_no");
                // 更新订单信息
                AccTradeRecord accTradeRecord = this.accTradeRecordMapper.selectAccTradeRecordByTradeNo(tradeNo);
                if(accTradeRecord.getStatus()==2){
                    accTradeRecord.setStatus(1);
                    accTradeRecord.setUpdateTime(DateUtils.getNowDate());
                    accTradeRecord.setUpdateBy("系统");
                    accTradeRecordMapper.updateAccTradeRecord(accTradeRecord);

                    //更新订单状态
                    long orderId = accTradeRecord.getTradeOrderId();
                    TradeOrder tradeOrder = this.tradeOrderMapper.selectTradeOrderById(orderId);
                    tradeOrder.setStatus(1);
                    tradeOrder.setUpdateTime(DateUtils.getNowDate());
                    tradeOrder.setUpdateBy("系统");
                    tradeOrderMapper.updateTradeOrder(tradeOrder);

                    //更新余额
                    //更新当前账户余额
                    AccUserAccount queryAccount = this.accUserAccountMapper.selectAccUserAccountByUserId(tradeOrder.getUserId());
                    queryAccount.setVersion(queryAccount.getVersion());
                    queryAccount.setBalance(tradeOrder.getAmount());//增加的金额
                    queryAccount.setUpdateBy("系统");
                    queryAccount.setUpdateTime(DateUtils.getNowDate());
                    accUserAccountMapper.recharge(queryAccount);

                    // 发送通知等
                    Map<String, String> xml = new HashMap<String, String>(2);
                    xml.put("return_code", "SUCCESS");
                    xml.put("return_msg", "OK");
                    xml.put("userId", accTradeRecord.getUserId()+"");
                    xml.put("amount", accTradeRecord.getAmount().toString());
                    return WxPayKit.toXml(xml);
                }
                return null;
            }
            return null;
        }
        return null;
    }

    @Override
    public LoginUser login(String phonenumber, String password) {
        //根据电话查询用户名
        SysUser user = this.sysUserMapper.selectUserByPhonenumber(phonenumber);
        if(user==null){
            throw new UserPasswordNotMatchException();
        }

        // 用户验证
        Authentication authentication = null;
        try {
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager
                    .authenticate(new UsernamePasswordAuthenticationToken(user.getUserName(),password));
        } catch (Exception e) {
            if (e instanceof BadCredentialsException) {
                throw new UserPasswordNotMatchException();
            } else {
                throw new CustomException(e.getMessage());
            }
        }
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        // 生成token
        String token = tokenService.createToken(loginUser);
        loginUser.setToken(token);
        return loginUser;
    }

    @Override
    public LoginUser freshUser(LoginUser user) {
        this.tokenService.refreshToken(user);
        user.setUser(this.sysUserMapper.selectUserById(user.getUser().getUserId()));
        return user;
    }

    @Override
    public SysUser updateUser(SysUser user) {
        this.sysUserMapper.updateUser(user);
        return user;
    }


}

